iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0

本篇內容來自於我在Medium上寫的一篇文章:Swift 語法再讀#1 [Between Struct and Class]

前言

最近在實作的過程中遇到很大觀念上的卡關,因此為了讓實作更加的順利,所以藉由回到官方文件、一些較有公信力的網路資料去重新研究這兩件事情的差異:

這篇文章大抵上會分成兩個重要的部分:

  1. 從程式碼舉例Struct、Class的差異
  2. Struct、Class最基本的特質與MVC架構應用上的差異

本文將參考至下列文章:

  1. 蘋果官方文件:Choosing Between Structures and Classes
    https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes

  2. 蘋果官方文件:Structures and Classes

https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes

  1. Swift Class vs Struct:設計 Model 時,該用 Struct 還是 Class 呢?
    https://www.appcoda.com.tw/swift-class/

正文

從程式碼的差異探討Struct、Class兩種不同的特性
原則上,我們可以知道上面的幾個文件都共同指出一個Struct、Class的很重要的特性,也就是Struct是以複製(Copy)而聞名、Class是以引用(Reference)而聞名。但是他們看起來都很像,要怎麼知道這是複製還是引用?

或許這要從程式碼開始解釋起:

let stre = 1 + 1 

從根本上來判斷兩個物件都在做一樣的事情,都是把結構或是類別實體化,然後也一起做了一件事:把textInClassA的someText屬性指為”TextChange”,這個時候我們在打印出來的文字後發現:
結構(Struct)中的實體,textInStructA、textInStructB居然是兩個不同的東西,打印出兩個不同的內容。

而類別(Class)中的實體,textInClassA、textInClassB則是相同的東西,打印出一樣的內容。

我想這個就要回到本質來討論,Struct的本質是複製,因此在改變textInStructA的someText內容後,其實改變的就只是textStructA本身而已,textStructB並不會因此受到影響,因為它是一個「完全的複製」,從textStructA上複製它的內容。

所以換句話說,textInStructA、textInStructB兩者是兩個不一樣的實體,它們都從同一個結構複製了內容,所以兩者若是互相改動,是不會互相牽絆的。

但在Class裡並不一樣,它是一個參考,而實論為什麼改動textInClassA會牽動整個值的變動?以下是來自於文章的解答:

Class 是參考型別,它會複製一份參考,然後建立一個共享實例。在複製後,兩個變數會共同參照同一份資料的實例,因此調整第二個變數的資料時,也會影響原本的變數。

Class 是參考型別,也就是說,一個 Class 型別的變數不會儲存實際的實例,但會儲存一個參考到記憶體 (heap) 儲存實例的位置。

兩者的複製、參考的不同特性,導致了我們今日在MVC架構中使用Struct、Class兩者上有截然不同的認知。

MVC架構中的Struct、Class

在蘋果官方的文件中,提到了什麼時候使用Struct、什麼時候使用Class,這個答案基本上是依照Struct、Class本身的本質下去延伸的。
在常見的Model中,Struct會是經常看到的東西,蘋果官網在Choosing Between Structures and Classes 一文中有一些解釋:

  • Use structures by default. 在默認的情況下使用結構
  • Use classes when you need Objective-C interoperability.在需要使用OC的的時候選用class
  • Use classes when you need to control the identity of the data you’re modeling.當您需要控制正在建模的數據的身份時使用類。
  • Use structures along with protocols to adopt behavior by sharing implementations.使用結構和協議通過共享實現來採用行為。

為什麼會是這樣呢?

由於Struct的特性是複製,它的原理會相較之下簡單,因為它是複製,所以假若我在ViewController中調用了一個Model中,由Struct定義的物件,那它在ViewController裡面調用時,就會是一個複製的概念,這也是為什麼在MVC架構中,我們經常稱Model是一個資料的「藍圖」,我們會在這個藍圖中確認我們需要哪些東西,然後再由ViewController調用,這樣的好處是我們不會有其他連動的問題,因為Struct是複製的。

然而ViewController作為一個文件,它能不能使用Struct呢?這個答案或許不能直接回答可以或不可以,在常見的做法中,都是以Class作為使用,其理由是參考型別的,也就是說,我們假若實體化了Class的內容,它會是參考原先的Class的實體位址。而反過來說,我們若是使用了Struct的話,則會產生一個現象,就是每次的指派都會產生一個新的實體,這會造成一件事情:混淆。

我們會不知道我們所指派的內容究竟源於何處,因為它是一個複製的實體。但Class則是參考某個遠端的實體,所以就特性來說,文件選擇以Class作為實體化才能發揮繼續存在的功能。
Model可以使用Class嗎?

可以,但相應的必須付出代價:也就是是所有的資料會變成是參考的,但這樣會讓程式的撰寫發生更多偵錯的複雜性,不過在初學者階段可能還不會以Class作為主要撰寫Model的方式。這邊就先不提了。未來遇到的時候會更多深入的討論。

以雲端連線、離線文件來比喻

Class的概念就像以前電腦教室上課時那樣,所有的人看到的資料都是來自老師那台電腦,所以我們看到的資料並不是真的那份資料,而是經由傳輸,參考自老師那台的。

Struct則是離線文件的概念,一開始的文件只有老師一個人擁有,但他如果要讓同學修改或填寫的話,必須拷貝一份出去,才能給其他人寫,然後再給老師,老師再決定要不要以修改過的拷貝文件作為取代。

所以,Struct、Class的選用會是一個重要的議題,但大部分的情況下,我們都是以在Model裡作為主要設置,而在ViewController裡則是以Class作為主要的設置,因此構成了MVC架構現在的樣子。

tags: 鐵人賽

上一篇
# Day18--如果我早一點追求MVC小姊姊,我就不會亂寫了
下一篇
#Day20--那些年,我們一起犯的傻
系列文
Swift30天:從語法到觀念,告訴你在踏入實作前最好弄清楚的那些事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言